package com.xhwl.data.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhwl.common.dto.cent.sdata.AccountDTO;
import com.xhwl.common.dto.cent.sdata.GroupDTO;
import com.xhwl.common.exception.BusinessException;
import com.xhwl.common.exception.DataException;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.sdata.Account;
import com.xhwl.common.pojo.cent.sdata.Group;
import com.xhwl.common.pojo.cent.sdata.GroupAccount;
import com.xhwl.common.query.cent.sdata.AccountQuery;
import com.xhwl.common.query.cent.sdata.GroupQuery;
import com.xhwl.common.vo.cent.sdata.GroupCountVO;
import com.xhwl.data.dao.IGroupAccountDao;
import com.xhwl.data.dao.IGroupDao;
import com.xhwl.data.service.IAccountService;
import com.xhwl.data.service.IGroupAccountService;
import com.xhwl.data.service.IGroupService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author JCccc
 * @Description
 * @Date 2021/6/15 13:48
 */
@Service
public class GroupServiceImpl extends ServiceImpl<IGroupDao, Group> implements IGroupService {
    private static final Logger log = LoggerFactory.getLogger(AccountServiceImpl.class);
    @Autowired
    IGroupAccountService groupAccountService;
    @Autowired
    IGroupDao groupDao;
    @Autowired
    IGroupAccountDao groupAccountDao;
    @Autowired
    IAccountService accountService;

    /**
     * 新增用户组
     *
     * @param groupDTO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultJson createGroup(GroupDTO groupDTO) {
        Optional.ofNullable(groupDTO.getProjectId()).orElseThrow(() -> new DataException("项目id不能为空"));
        Optional.ofNullable(groupDTO.getName()).orElseThrow(() -> new DataException("用户组名称不能为空"));
        Optional.ofNullable(groupDTO.getIndustryId()).orElseThrow(() -> new DataException("业态id不能为空"));
        Group group = new Group();
        BeanUtils.copyProperties(groupDTO, group);
        //1.验重
        checkExist(group);
        //2. 新增用户组
        boolean save = save(group);
        if (!save) {
            return ResultJson.fail("操作失败");
        }
        Integer groupId = group.getId();
        //3.新增用户组关联的账号数据
        if (!CollectionUtils.isEmpty(groupDTO.getAccountIds())) {
            List<Integer> accountIds = groupDTO.getAccountIds();
            groupAccountService.createGroupAccount(groupId, accountIds);
        }
        return ResultJson.success(groupId);
    }

    /**
     * 修改用户组
     *
     * @param groupDTO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultJson updateGroup(GroupDTO groupDTO) {
        Optional.ofNullable(groupDTO.getId()).orElseThrow(() -> new DataException("id不能为空"));

        Group group = new Group();
        BeanUtils.copyProperties(groupDTO, group);
        //1.验重
        checkExist(group);
        //2.更新
        boolean updateResult = updateById(group);
        if (!updateResult) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new BusinessException("操作失败");
        }
        //3.是否需要更新账号关联关系
        if (!CollectionUtils.isEmpty(groupDTO.getAccountIds())) {
            //先删后增
            groupAccountService.createGroupAccount(group.getId(), groupDTO.getAccountIds());
        }
        return ResultJson.success("操作成功");
    }

    /**
     * 删除用户组
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultJson deleteGroup(Integer id) {
        groupDao.deleteById(id);
        groupAccountService.deleteGroupAccount(Arrays.asList(id), null);
        return ResultJson.success("操作成功");
    }

    /**
     * 分页
     *
     * @param page
     * @param groupQuery
     * @return
     */
    @Override
    public Page<GroupDTO> getPageList(Page page, GroupQuery groupQuery) {

        //处理需要查询id集合
        Set<Integer> needQueryGroupIds = new HashSet<>();
        if (!CollectionUtils.isEmpty(groupQuery.getAccountIds())) {
            List<GroupAccount> groupAccounts = groupAccountService.getList(null, groupQuery.getAccountIds());
            for (GroupAccount groupAccount : groupAccounts) {
                needQueryGroupIds.add(groupAccount.getGroupId());
            }
        }
        if (!CollectionUtils.isEmpty(groupQuery.getIdList())) {
            needQueryGroupIds.addAll(groupQuery.getIdList());
        }
        if (CollectionUtils.isEmpty(needQueryGroupIds)) {
            groupQuery.setIdList(new ArrayList<>(needQueryGroupIds));
        }
        Page<GroupDTO> groupPageList = groupDao.getPageList(page, groupQuery);
        List<GroupDTO> records = groupPageList.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return groupPageList;
        }
        fillAccountIds(records);
        return groupPageList;
    }


    /**
     * 不分页
     *
     * @param groupQuery
     * @return
     */
    @Override
    public List<GroupDTO> getList(GroupQuery groupQuery) {

        //处理需要查询id集合
        Set<Integer> needQueryGroupIds = new HashSet<>();
        if (!CollectionUtils.isEmpty(groupQuery.getAccountIds())) {
            List<GroupAccount> groupAccounts = groupAccountService.getList(null, groupQuery.getAccountIds());
            for (GroupAccount groupAccount : groupAccounts) {
                needQueryGroupIds.add(groupAccount.getGroupId());
            }
        }
        if (!CollectionUtils.isEmpty(groupQuery.getIdList())) {
            needQueryGroupIds.addAll(groupQuery.getIdList());
        }
        if (!CollectionUtils.isEmpty(needQueryGroupIds)) {
            groupQuery.setIdList(new ArrayList<>(needQueryGroupIds));
        }
        List<GroupDTO> records = groupDao.getList(groupQuery);
        if (CollectionUtils.isEmpty(records)) {
            return records;
        }
        fillAccountIds(records);
        return records;
    }

    /**
     * 根据id获取组信息
     *
     * @param id
     * @return
     */
    @Override
    public GroupDTO getById(Integer id) {
        GroupDTO groupDTO = groupDao.getById(id);
        if (null == groupDTO) {
            log.info("当前用户组不存在 id={}", id);
            return null;
        }
        List<GroupDTO> records = Arrays.asList(groupDTO);

        fillAccountIds(records);
        groupDTO = records.get(0);
        return groupDTO;
    }

    /**
     * 根据用户组id统计出关联的账号数
     *
     * @param projectId
     * @param applicationName
     * @return
     */
    @Override
    public List<GroupCountVO> getCountList(Integer projectId, String applicationName) {
        return groupDao.getCountList(projectId, applicationName);
    }

    @Override
    public Page<Account> getGroupAccPage(Page page, GroupQuery query) {
        return groupDao.getGroupAccPage(page,query);
    }

    @Override
    public Page<Group> page(Page page, GroupQuery groupQuery) {
        QueryWrapper<Group> queryWrapper = new QueryWrapper<>();
        if (null != groupQuery.getName()) {
            queryWrapper.eq("name", groupQuery.getName());
        }
        if (null != groupQuery.getProjectId()) {
            queryWrapper.eq("project_id", groupQuery.getProjectId());
        }
        if (null != groupQuery.getApplicationName()) {
            queryWrapper.eq("application_name", groupQuery.getApplicationName());
        }
        return groupDao.selectPage(page, queryWrapper);
    }

    /**
     * 验重 ,规则：项目下,用户名是否重复
     *
     * @param group
     */
    public void checkExist(Group group) {
        QueryWrapper<Group> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("project_id", group.getProjectId());
        queryWrapper.eq("name", group.getName());
        Group groupDb = groupDao.selectOne(queryWrapper);
        if (null != groupDb) {
            //修改，id不等于自己的id就是重复
            if (null != group.getId()) {
                if (!groupDb.getId().equals(group.getId())) {
                    throw new DataException("用户组名称已重复");
                }
            } else {
                //新增 ，存在就是重复
                throw new DataException("用户组名称已重复");
            }
        }
    }

    public void fillAccountIds(List<GroupDTO> records) {
        List<Integer> groupIds = records.stream().map(e -> e.getId()).collect(Collectors.toList());
        QueryWrapper<GroupAccount> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("group_id", groupIds);
        List<GroupAccount> groupAccounts = groupAccountDao.selectList(queryWrapper);

        List<Integer> accountIdsAll = groupAccounts.stream().map(GroupAccount::getAccountId).collect(Collectors.toList());
        Set<Integer> accountIdsSet = new HashSet<>(accountIdsAll);
        //当所有组内都没有人员时 避免查出所有人员导致耗时过久
        if (CollectionUtils.isEmpty(accountIdsSet)) {
            return;
        }
        AccountQuery accountQuery = new AccountQuery();
        accountQuery.setIdList(new ArrayList<>(accountIdsSet));
        List<AccountDTO> accountList = accountService.getList(accountQuery);
        accountList = accountList.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(AccountDTO::getId))),
                ArrayList::new));
        Map<Integer, AccountDTO> accountMap = accountList.stream().collect(Collectors.toMap(AccountDTO::getId, Function.identity()));

        Map<Integer, List<Integer>> accountIdsMap = new HashMap<>(groupAccounts.size());
        for (GroupAccount groupAccount : groupAccounts) {
            Integer groupId = groupAccount.getGroupId();
            if (null == accountIdsMap.get(groupId)) {
                List<Integer> accountIds = new ArrayList<>();
                accountIds.add(groupAccount.getAccountId());
                accountIdsMap.put(groupId, accountIds);
            } else {
                List<Integer> accountIds = accountIdsMap.get(groupId);
                Set<Integer> accountSet = new HashSet<>(accountIds);
                accountSet.add(groupAccount.getAccountId());
                accountIdsMap.put(groupId, new ArrayList<>(accountSet));
            }
        }
        for (GroupDTO groupDTO : records) {
            Integer groupId = groupDTO.getId();
            if (null != accountIdsMap.get(groupId)) {
                List<Integer> accountIds = accountIdsMap.get(groupId);
                groupDTO.setAccountIds(accountIds);
                List<AccountDTO> accounts = new ArrayList<>();
                for (Integer accountId : accountIds) {
                    if (null != accountMap.get(accountId)) {
                        AccountDTO account = accountMap.get(accountId);
                        account.setPassword(null);
                        accounts.add(account);
                    }
                }
                groupDTO.setAccounts(accounts);
            }

        }
    }
}
